{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[Parameter containing:\n",
      "tensor([[[[ 0.3686, -0.4266],\n",
      "          [-0.1505, -0.4382]]],\n",
      "\n",
      "\n",
      "        [[[ 0.2204,  0.0246],\n",
      "          [-0.0874, -0.2878]]]], requires_grad=True)]\n",
      "tensor([[[[ 0.2181, -0.8648,  0.2181],\n",
      "          [-0.0696, -0.5771, -0.0696],\n",
      "          [-0.8648,  0.2181, -0.8648]],\n",
      "\n",
      "         [[ 0.1330, -0.2632,  0.1330],\n",
      "          [-0.0675, -0.0628, -0.0675],\n",
      "          [-0.2632,  0.1330, -0.2632]]]], grad_fn=<ThnnConv2DBackward>)\n"
     ]
    }
   ],
   "source": [
    "# 1. Conv2d test\n",
    "import torch\n",
    "import torch.nn as nn\n",
    "\n",
    "#input1 = torch.tensor([[1,2,3],[4,5,6],[7,8,9]]).float()\n",
    "input1 = torch.tensor([[1,0,1,0],[1,0,1,0],[0,1,0,1],[0,1,0,1]]).float()\n",
    "input2=input1.reshape([1,1,4,4])\n",
    "#input2=torch.ones((1,1,3,3))\n",
    "\n",
    "#input2.dtype\n",
    "m = nn.Conv2d(1,2,2,stride=(1,1),padding=0,dilation=1,groups=1,bias=False)\n",
    "print(list(m.parameters()))\n",
    "print(m(input2))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 83,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 2.transforms.Compose test\n",
    "import torch\n",
    "from torchvision import transforms\n",
    "from PIL import Image\n",
    "img = Image.open('test1.jpg')\n",
    "img.show()\n",
    "#trans = transforms.Compose([transforms.RandomCrop(28,padding=4)])\n",
    "trans = transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010))\n",
    "img2 = trans(img)\n",
    "img2.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([ 1.4488, -1.3835,  1.0511, -0.3202], requires_grad=True)\n",
      "tensor([ 2.8976, -2.7670,  2.1021, -0.6405])\n"
     ]
    }
   ],
   "source": [
    "# 3. torch.autograd.Function test\n",
    "import torch\n",
    "input1 = torch.randn(4,requires_grad = True)\n",
    "# 平方，累加\n",
    "output = input1\n",
    "loss = output.pow(2).sum()\n",
    "loss.backward()\n",
    "\n",
    "print(input1)\n",
    "print(input1.grad)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([ 1.4488, -1.3835,  1.0511, -0.3202], requires_grad=True)\n",
      "tensor([0., 0., 0., 0.])\n"
     ]
    }
   ],
   "source": [
    "# 平方，量化，累加\n",
    "input1.grad.data.zero_()  # 梯度清零\n",
    "output = torch.round(input1*8)/8\n",
    "loss = output.pow(2).sum()\n",
    "loss.backward()\n",
    "print(input1)\n",
    "print(input1.grad)  #无法求导"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([ 1.4488, -1.3835,  1.0511, -0.3202], requires_grad=True)\n",
      "tensor([ 1.5000, -1.3750,  1.0000, -0.3750], grad_fn=<Quan8Backward>)\n",
      "tensor([ 3.0000, -2.7500,  2.0000, -0.7500])\n"
     ]
    }
   ],
   "source": [
    "# 重新定义反向传播函数\n",
    "class Quan8(torch.autograd.Function):\n",
    "    \n",
    "    @staticmethod\n",
    "    #ctx是默认参数，input不是，可以为任意字符串变量，只是习惯都这么写的而已\n",
    "    def forward(ctx,input):  #静态修饰器，用该方法的类无需实例化即可调用\n",
    "        return torch.round(input*8)/8\n",
    "    @staticmethod\n",
    "    def backward(ctx,grad_output):\n",
    "        return grad_output\n",
    "\n",
    "input1.grad.data.zero_()  # 梯度清零\n",
    "output = Quan8.apply(input1)\n",
    "loss = output.pow(2).sum()\n",
    "loss.backward()\n",
    "print(input1)\n",
    "print(output)\n",
    "print(input1.grad)  #可以求导"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "[自定义层](https://www.cnblogs.com/yymn/articles/8245110.html)\n",
    "\n",
    "[pytorch实现简单的straight-through estimator(STE)](https://segmentfault.com/a/1190000020993594)\n",
    "\n",
    "[pytorch进阶：常用类API源码理解和功能使用](https://blog.csdn.net/mingqi1996/article/details/87889403)\n",
    "\n",
    "[在pytorch和tf里自定义forward和backward](https://zhuanlan.zhihu.com/p/350217951)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "27.5"
      ]
     },
     "execution_count": 36,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "55/2"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python [conda env:root] *",
   "language": "python",
   "name": "conda-root-py"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.4"
  },
  "varInspector": {
   "cols": {
    "lenName": 16,
    "lenType": 16,
    "lenVar": 40
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "oldHeight": 291.183666,
   "position": {
    "height": "40px",
    "left": "683.667px",
    "right": "20px",
    "top": "90px",
    "width": "538.333px"
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "varInspector_section_display": "none",
   "window_display": true
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
